/*
 * Created by IntelliJ IDEA.
 * User: sguo
 * Date: Nov 18, 2003
 * Time: 2:35:38 PM
 * To change template for new class use
 * Code Style | Class Templates options (Tools | IDE Options).
 */

import java.util.*;
import lpc2xxx.hw.*;

public class Sort {

    static String newLineString = System.getProperty("line.separator", "\r\n");
    static byte[] newLineBytes = newLineString.getBytes();

    public static int FLAG_APPROVED           =0x0001;
    public static int FLAG_DECLINED           =0x0002;
    public static int FLAG_REFERAL            =0x0004;
    public static int FLAG_FORCE_POST         =0x0008;
    public static int FLAG_FORCE_POST_UNDER   =0x0010;
    public static int FLAG_FORCE_POST_OVER    =0x0020;
    public static int FLAG_SAF                =0x0040;
    public static int FLAG_SWIPED             =0x0080;
    public static int FLAG_VOIDED             =0x0100;
    public static int FLAG_COMPLETED          =0x0200;
    public static int FLAG_CHEQUING_ACCOUNT   =0x0400;
    public static int FLAG_SAVINGS_ACCOUNT    =0x0800;
    public static int FLAG_ENGLISH_CUSTOMER   =0x1000;
    public static int FLAG_FRENCH_CUSTOMER    =0x2000;

    public static int	STATUS_TRANS_NOT_APPROVED		=0;	// not approved, initial status
    public static int	STATUS_TRANS_APPROVED			=1;	// approved, can be committed after ACK is securely send out
    public static int	STATUS_TRANS_COMMITABLE			=2;	// can be commited
    public static int	STATUS_TRANS_COMMITTED			=3;	// committed already

// Batch storage sizes
    public static int FIELD_BUFFER_LENGTH =30;
    public static int ID_SIZE             =3;
    public static int INVOICE_NUM_SIZE    =10;
    public static int AUTH_NUM_SIZE       =8;
    public static int PAN_SIZE            =10;
    public static int EXPIRY_SIZE         =4;
    public static int DATE_SIZE           =6;
    public static int TIME_SIZE           =6;
    public static int AMOUNT_SIZE         =4;
    public static int TRANS_TYPE_SIZE     =1;
    public static int CARD_TYPE_SIZE      =2;
    public static int BATCH_NUM_SIZE      =3;
    public static int SHIFT_NUM_SIZE      =3;
    public static int SEQU_NUM_SIZE       =3;
    public static int TRANS_FLAG_SIZE     =4;
    public static int TRANS_CODE_LEN      =2;

    public static int STORAGE_MAX_NUM_OF_REC		= 40;

	final String Dot = ". ";
	final String DotDot = "..";
	final String Empty = "";
	final String STRING_DP = "DP";
	final String STRING_VI = "VI";

    class t_BATCH
    {
        public String        szUserId = null;
        public String        szInvoiceNumber= null;
        public String        szAuthNumber = null;
        public String        szPan = null;
        public String        szExpiry = null;
        public String        szDate = null;
        public String        szTime = null;
        public int uiBaseAmount;
        public int uiTipAmount;
        public int uiCashBackAmount;
        public int uiTotalAmount;
        public int  uiTransactionType;
        public String        szCardType = null;
        public String        szBatchNumber = null;
        public String        szShiftNumber = null;
        public String        szSequenceNumber = null;
        public int uiTransactionFlags;
    } ;


    public t_BATCH[] tBatch = new t_BATCH[STORAGE_MAX_NUM_OF_REC];
    public int[] g_uiBatchIndex = new int[STORAGE_MAX_NUM_OF_REC];
    public int g_uiBatchCount;


    class TCondition
    {
        public int	uiFieldIndex;		//	the index that a field in batch record.
        public String		vKeyValue;			//	the search condition is this value must equal the
        public int	uiValueSize;		//	the size of keyvalue
    };

    class tTRANS_INFO
    {
        public int uintScreenTextId;
        public int uintReceiptTextId;
        public int uintTransactionCode;
        public String tchTransactionCode = new String  ();

    };

/* Enums for transaction types */
        final public static int eTRANTYPE_Trans_Type_Min = 0,

            eTRANTYPE_Finan_Min = 1,

                eTRANTYPE_Purchase = 2,
                eTRANTYPE_Pre_Auth = 3,
                eTRANTYPE_Pre_Auth_Compl = 4,
                eTRANTYPE_Phone_Mail_Order = 5,
                eTRANTYPE_Return = 6,
                eTRANTYPE_Cash_Advance = 7,
                eTRANTYPE_Card_Verification = 8,
                eTRANTYPE_Funds_Avail_Enq = 9,
                eTRANTYPE_Void_Purchase = 10,
                eTRANTYPE_Void_Return = 11,
                eTRANTYPE_Cash_Advance_Adj = 12,

            eTRANTYPE_Finan_Max = 13,

            eTRANTYPE_Admin_Min = 14,
                eTRANTYPE_Close_Batch = 15,
                eTRANTYPE_Batch_Subtotals = 16,
                eTRANTYPE_Download = 17,
            eTRANTYPE_Admin_Max = 18,

        eTRANTYPE_Trans_Type_Max = 19;

/*
 * The array to hold the transaction types and the pointers to the request
 * message formats
 */
//    public tTRANS_INFO[] tTransactionInfoArray=new tTRANS_INFO[eTRANTYPE_Trans_Type_Max + 1];
    public tTRANS_INFO[] tTransactionInfoArray = null;

        final public static int eSTORE_ID = 0,
        eSTORE_INVOICE_NUMBER = 1,
        eSTORE_AUTH_NUMBER = 2,
        eSTORE_PAN = 3,
        eSTORE_EXPIRY = 4,
        eSTORE_DATE = 5,
        eSTORE_TIME = 6,
        eSTORE_BASE_AMT = 7,
        eSTORE_TIP_AMT = 8,
        eSTORE_CASHBACK_AMT = 9,
        eSTORE_TOTAL_AMT = 10,
        eSTORE_TRANS_TYPE = 11,
        eSTORE_CARD_TYPE = 12,
        eSTORE_BATCH_NUM = 13,
        eSTORE_SHIFT_NUM = 14,
        eSTORE_SEQU_NUM = 15,
        eSTORE_TRANS_FLAG = 16;

    public String  gtstrCurTransDate=null;
    public String  gtstrCurTransTime=null;
    public String  gtstrCurTransPAN=null;
    public String  gtstrCurTransExpiry=null;
    public String  gtstrCurTransCardType=null;
    public int guiCurTransBaseAmount;
    public int guiCurTransTipAmount;
    public int guiCurTransCashBackAmount;
    public int guiCurTransTotalAmount;
    public String  gtstrRRNShiftNum=null;
    public String  gtstrRRNBatchNum=null;
    public String  gtstrRRNSeqNum=null;
    public String   gtstrCurTransOpId=null;
    public String   gtstrCurTransInvoiceNum=null;
    public int  guiTransactionFlags;
    public int   guiCurTransType;
    public int  guiHostSequenceNumber;
    public int  guiHostBatchNumber;
    public int  guiHostShiftNumber;
    public String  gtstrCurTransAuth=null;
/*
 * Not SUPPORTED - find a replacement Calendar class
    public Calendar  gtCurTransDate;
 */
    public int  guiRecordNumber;

// Global buffers for all components to use
    public String  gptchBuffer = new String ();
    public String  gptchSmallBuffer = null;

    Sort ()
    {

// DEBUG

Console.println ("Enter Sort: " + STORAGE_MAX_NUM_OF_REC + " records");

int i;
        for (i=0; i<STORAGE_MAX_NUM_OF_REC; i++)
            tBatch[i] = new t_BATCH ();

// Console.println ("created tBatch");

        guiRecordNumber = 0;
        g_uiBatchCount = 0;

        // Set the initial values for the transactions.
        guiHostBatchNumber = 1;
        guiHostShiftNumber = 2;

        // Fill the batch
        FillBatch();
    }

    public static void main (String args[])
    {
        //TCondition tCond;
        int[] uiSortCondition = new int[4];
        int uiRecNum;

        Sort t = new Sort ();


        // Clear the batch
        // Sort the batch
        uiSortCondition[0] = t.eSTORE_TRANS_TYPE;
        uiSortCondition[1] = t.eSTORE_CARD_TYPE;
        uiSortCondition[2] = t.eSTORE_INVOICE_NUMBER;
        uiSortCondition[3] = t.eSTORE_TOTAL_AMT;


		int time_before = System.currentTimeMillis();
		//int time_before = System.currentTimeMillis();
		Console.println ("\n\r Sort Batch Start Time (ticks)[" + time_before + "ms]\n");

		Console.println ("Sort batch start\n");
        uiRecNum = t.RetrieveEx(null, (int)0, uiSortCondition, (int)4);
		Console.println ("Sort batch stop\n");


		int time_after = System.currentTimeMillis();
		//int time_after = System.currentTimeMillis();
        Console.println ("\n\r Sort Batch End Time (ticks)[" + time_after + "ms]\n");
		Console.println ("Total time: " + (time_after - time_before));

	Console.println("Exit Sort\n\r");

    }

/*---------------------------------------------------------------------------------------*/
final String STRING_999 = "999";
final String STRING_4520840000000044 = "4520840000000044";
final String STRING_0506 = "0506";
final String STRING_000 = "000";
final String STRING_38555565130001 = "38555565130001";
final String STRING_371449635398449 = "371449635398449";
final String STRING_0110 = "0110";
final String STRING_AX = "AX";
final String STRING_5191230005918066 = "5191230005918066";
final String STRING_1208 = "1208";
final String STRING_MC = "MC";
final String STRING_0611 = "0611";
final String STRING_DC = "DC";
final String STRING_00 = "00";

    public void FillBatch()
    {
        int iIndex;
        int iLength;
        int uiClockTicks=0x1234;

// DEBUG
Console.println ("Enter FillBatch");

        // Values that do not change
        gtstrCurTransOpId = STRING_999;
        gtstrCurTransPAN = STRING_4520840000000044;
        gtstrCurTransExpiry = STRING_0506;
        guiCurTransCashBackAmount = 0;
        guiCurTransType = eTRANTYPE_Purchase;
        gtstrCurTransCardType = STRING_VI;
        String sTmp = STRING_000 + Integer.toString (guiHostBatchNumber);
        gtstrRRNBatchNum = sTmp.substring (sTmp.length()-3, sTmp.length ());
        sTmp = STRING_000 + Integer.toString (guiHostShiftNumber);
        gtstrRRNShiftNum = sTmp.substring (sTmp.length()-3, sTmp.length ());
        guiTransactionFlags = FLAG_APPROVED |
                              FLAG_SWIPED |
                              FLAG_ENGLISH_CUSTOMER;


/*
 * Not SUPPORTED - find a replacement Calendar class
 *
 		String sYear, sMonth, sDay;
		gtCurTransDate = Calendar.getInstance ();
		sYear= Integer.toString(gtCurTransDate.get(Calendar.YEAR));
		sMonth = (STRING_00 + gtCurTransDate.get(Calendar.MONTH));
		sDay = (STRING_00 + gtCurTransDate.get(Calendar.DAY_OF_MONTH));

		gtstrCurTransDate =
			sYear.substring (2,4)+
			sMonth.substring (sMonth.length()-2, sMonth.length ()) +
			sDay.substring (sDay.length ()-2, sDay.length ());
 */


        for(iIndex = 0; iIndex < STORAGE_MAX_NUM_OF_REC; iIndex++)
        {
// DEBUG
// Console.println ("FillBatch: iIndex = " + iIndex);

            // Set the card data
/* if CLOCK
            uiClockTicks = Clock.getTickCount ();

            if((uiClockTicks % 4) == 0)
            {
                gtstrCurTransPAN = STRING_38555565130001;
                gtstrCurTransExpiry = STRING_0611;
                gtstrCurTransCardType = STRING_DC;
            }
            else if((uiClockTicks % 3) == 0)
            {
                gtstrCurTransPAN = STRING_371449635398449;
                gtstrCurTransExpiry = STRING_0110;
                gtstrCurTransCardType = STRING_AX;
            }
            else if((uiClockTicks % 2) == 0)
            {
                gtstrCurTransPAN = STRING_5191230005918066;
                gtstrCurTransExpiry = STRING_1208;
                gtstrCurTransCardType = STRING_MC;
            }
            else
            {
                gtstrCurTransPAN = STRING_4520840000000044;
                gtstrCurTransExpiry = STRING_0506;
                gtstrCurTransCardType = STRING_VI;
            }
*/


            // Set the data
/* if CLOCK
            uiClockTicks = Clock.getTickCount ();
            gtstrCurTransInvoiceNum = Integer.toString(uiClockTicks&0xfff);
 */
            gtstrCurTransInvoiceNum = Integer.toString(uiClockTicks&0xff);

/* if CLOCK
            uiClockTicks = Clock.getTickCount ();
 */
            gptchSmallBuffer = ("00000000" + Integer.toString(uiClockTicks)).substring(0, 8);
// Console.println ("FillBatch: after curTrans");
//            gtstrCurTransAuth =  gptchSmallBuffer;
            gtstrCurTransAuth =  ("00000000" + Integer.toString(uiClockTicks)).substring(0, 8);

// Console.println ("FillBatch: set the data");

// DEBUG
// Console.println ("FillBatch: gtCurTransDate = ...");

            String sHour, sMinute, sSecond;

			sHour = "01";
			sMinute = "01";
			sSecond = "01";
// DEBUG
// Console.println ("FillBatch: sYear = ...");
// Console.println ("FillBatch: sYear");

/*
 * Not SUPPORTED - find a replacement Calendar class
            sHour = (STRING_00+ gtCurTransDate.get(Calendar.HOUR));
            sMinute = (STRING_00+ gtCurTransDate.get(Calendar.MINUTE));
            sSecond = (STRING_00+ gtCurTransDate.get(Calendar.SECOND));
 */

// DEBUG
// Console.println ("FillBatch: gtstrCurTransTime = ...");

            gtstrCurTransTime =
                sHour.substring (sHour.length ()-2, sHour.length ()) +
                    sMinute.substring (sMinute.length()-2, sMinute.length ()) +
                    sSecond.substring (sSecond.length ()-2, sSecond.length ());

// Console.println ("FillBatch: CurTransTime");

/* if CLOCK
            uiClockTicks = Clock.getTickCount ();
*/
            gptchSmallBuffer = Integer.toString(uiClockTicks);
            iLength = gptchSmallBuffer.length ();

            guiCurTransBaseAmount = uiClockTicks & 0x000000FF;
            guiCurTransTipAmount = 0;
            guiCurTransTotalAmount = guiCurTransBaseAmount + guiCurTransTipAmount + guiCurTransCashBackAmount;

// Console.println ("FillBatch: sTmp");
// DEBUG
// Console.println ("FillBatch: sTmp = ...");

            sTmp = STRING_000 + guiHostSequenceNumber++;
            gtstrRRNSeqNum = sTmp.substring (sTmp.length ()-3, sTmp.length ());

// DEBUG
// Console.println ("FillBatch: Add the record to the batch");

            // Add the record to the batch
            if(SaveToBatch() == false)
            {
                Console.println ("\n\r Error with Record " + iIndex);
            }
            else
            {
/*
                Console.println ("\n\r" +
		                   gtstrCurTransPAN+","+ gtstrCurTransExpiry+","+ gtstrCurTransCardType+","+
                           gtstrCurTransInvoiceNum+","+ gtstrCurTransAuth+","+
                           gtstrCurTransDate+","+ gtstrCurTransTime+","+
                           guiCurTransBaseAmount+","+ guiCurTransTipAmount+","+
                           guiCurTransCashBackAmount+","+ guiCurTransTotalAmount+","+
                           gtstrRRNSeqNum);
 */
            }

        }
Console.println ("Exit FillBatch");
        return;
    }

/*---------------------------------------------------------------------------------------*/
    boolean SaveToBatch()
    {
        boolean bReturn;

        // add a new recoed
        guiCurTransTotalAmount = guiCurTransBaseAmount +  guiCurTransTipAmount + guiCurTransCashBackAmount;

        bReturn = AddRecord();

        return bReturn;
    }

/*---------------------------------------------------------------------------------------*/
    boolean AddRecord()
    {
        tBatch[guiRecordNumber].szUserId = gtstrCurTransOpId;
        tBatch[guiRecordNumber].szInvoiceNumber = gtstrCurTransInvoiceNum;
        tBatch[guiRecordNumber].szAuthNumber = gtstrCurTransAuth;
        tBatch[guiRecordNumber].szPan = gtstrCurTransPAN;
        tBatch[guiRecordNumber].szExpiry = gtstrCurTransExpiry;
        tBatch[guiRecordNumber].szDate = gtstrCurTransDate;
        tBatch[guiRecordNumber].szTime = gtstrCurTransTime;
        tBatch[guiRecordNumber].uiBaseAmount = guiCurTransBaseAmount;
        tBatch[guiRecordNumber].uiTipAmount = guiCurTransTipAmount;
        tBatch[guiRecordNumber].uiCashBackAmount = guiCurTransCashBackAmount;
        tBatch[guiRecordNumber].uiTotalAmount = guiCurTransTotalAmount;
        tBatch[guiRecordNumber].uiTransactionType = guiCurTransType;
        tBatch[guiRecordNumber].szCardType = gtstrCurTransCardType;
        tBatch[guiRecordNumber].szBatchNumber = gtstrRRNBatchNum;
        tBatch[guiRecordNumber].szShiftNumber = gtstrRRNShiftNum;
        tBatch[guiRecordNumber].szSequenceNumber = gtstrRRNSeqNum;
        tBatch[guiRecordNumber].uiTransactionFlags = guiTransactionFlags;

        guiRecordNumber++;
        return true;
    }

/*---------------------------------------------------------------------------------------*/

    public int RetrieveEx(TCondition [] tCond,
                           int uiCondNum,
                           int [] tSortCond,
                           int uiSortCondNum)
    {
        int i;
        int j;
        int iInsertIndex;
        int iHeadIndex;
        int iTailIndex;
        int iResult = 0;
        int eStatus;
        boolean bFound;
        String uiBufferOutData=new String();
        String uiBufferInData=new String();

        for(i = 0; i < guiRecordNumber; i++)
        {

// DEBUG
// Console.println ("RetrieveEx: i = " + i);

            bFound=true;
            for (j=0;j<uiCondNum;j++)
            {
                uiBufferInData=BatchReadFieldFS(tCond[j].uiFieldIndex, i);
				uiBufferOutData = tCond[j].vKeyValue;
                if (uiBufferInData ==null )
                {
                    return 0;
                }
                if (!uiBufferInData.equals(uiBufferOutData))
                {
                    bFound=false;
                    break;
                }
            }

            if (bFound)
            {
                if (uiSortCondNum!=0)
                {
                    iHeadIndex=0;
                    iTailIndex=g_uiBatchCount-1;
                    while (iHeadIndex<=iTailIndex&&g_uiBatchCount>0)
                    {
                        iInsertIndex=(iHeadIndex+iTailIndex)/2;
                        for (j=0;j<uiSortCondNum;j++)
                        {
                            iResult=BatchFieldCmp(tSortCond[j],
                                i,g_uiBatchIndex[iInsertIndex]);
                            if (iResult!=0)
                            {
                                break;
                            }
                        }
                        if (iResult>=0)
                        {
                            iHeadIndex=iInsertIndex+1;
                        }
                        else
                        {
                            if (iResult<0)
                            {
                                iTailIndex=iInsertIndex-1;
                            }
                        }
                    }
                    iInsertIndex=iHeadIndex;
                    for (j=g_uiBatchCount;j>iInsertIndex;j--)
                    {
                        g_uiBatchIndex[j]=g_uiBatchIndex[j-1];
                    }
                    g_uiBatchCount++;
                    g_uiBatchIndex[iInsertIndex]=i;
                }
                else
                {
                    g_uiBatchIndex[g_uiBatchCount++]=i;
                }
            }
        }
        return g_uiBatchCount;
    }

/*---------------------------------------------------------------------------------------*/
    String BatchReadFieldFS(int uiFieldIndex,
                                int uiBatchIndex)
    {
        String puiField = null;

		switch (uiFieldIndex)
		{
			case eSTORE_ID:
                puiField = tBatch[uiBatchIndex].szUserId;
				break;
			case eSTORE_INVOICE_NUMBER:
                puiField =  tBatch[uiBatchIndex].szInvoiceNumber;
				break;
			case eSTORE_AUTH_NUMBER:
                puiField =  tBatch[uiBatchIndex].szAuthNumber;
				break;
			case eSTORE_PAN:
                puiField =  tBatch[uiBatchIndex].szPan;
				break;
			case eSTORE_EXPIRY:
                puiField =  tBatch[uiBatchIndex].szExpiry;
				break;
			case eSTORE_DATE:
                puiField =  tBatch[uiBatchIndex].szDate;
				break;
			case eSTORE_TIME:
                puiField =  tBatch[uiBatchIndex].szTime;
				break;
			case eSTORE_BASE_AMT:
                puiField = Integer.toString(tBatch[uiBatchIndex].uiBaseAmount);
				break;
			case eSTORE_TIP_AMT:
                puiField = Integer.toString (tBatch[uiBatchIndex].uiTipAmount);
				break;
			case eSTORE_CASHBACK_AMT:
                puiField = Integer.toString (tBatch[uiBatchIndex].uiCashBackAmount);
				break;
			case eSTORE_TOTAL_AMT:
                puiField = Integer.toString (tBatch[uiBatchIndex].uiTotalAmount);
				break;
			case eSTORE_TRANS_TYPE:
                puiField = Integer.toString (tBatch[uiBatchIndex].uiTransactionType);
				break;
			case eSTORE_CARD_TYPE:
                puiField =  tBatch[uiBatchIndex].szCardType;
				break;
			case eSTORE_BATCH_NUM:
                puiField =  tBatch[uiBatchIndex].szBatchNumber;
				break;
			case eSTORE_SHIFT_NUM:
                puiField =  tBatch[uiBatchIndex].szShiftNumber;
				break;
			case eSTORE_SEQU_NUM:
                puiField =  tBatch[uiBatchIndex].szSequenceNumber;
				break;
			case eSTORE_TRANS_FLAG:
                puiField = Integer.toString (tBatch[uiBatchIndex].uiTransactionFlags);
				break;
		}
        return puiField;
    }

/*------------------------------------------------------------------------------------------
 * Name:    BatchFieldCmp
 * Desc:    Compare a field in two batch record

 * @Param:  uiFieldIndex ,the field index of batch value
            uiBatchIndex1
            uiBatchIndex2, the batch record index

 * @Return: A int that greater than 0, when batch field value 1 is greater than value 2
            A integer equal 0, when batch field value 1 equal value 2
            A int less than 0, when batch field value 1 is less than value 2
------------------------------------------------------------------------------------------*/
    int BatchFieldCmp(int uiFieldIndex,int uiBatchIndex1,
                             int uiBatchIndex2)
    {
        String strField1;
        String strField2;

        int uiInvoiceNum1 = 0;
        int uiInvoiceNum2 = 0;
        int uiReturnValue = 0;

        // Read the data from the batch
        strField1 = BatchReadFieldFS (uiFieldIndex, uiBatchIndex1);
        strField2 = BatchReadFieldFS (uiFieldIndex, uiBatchIndex2);

        if (strField1 == null || strField2 == null) return 0;

        // Compare the data
        if (uiFieldIndex == eSTORE_CARD_TYPE)
        {
            if(strField1.equals(STRING_DP))
            {
                strField1 = Dot;
            }
            else if(strField1.equals(STRING_VI))
            {
                strField1 = DotDot;
            }
            if(strField2.equals(STRING_DP))
            {
                strField2 = Dot;
            }
            else if(strField2.equals(STRING_VI))
            {
                strField2 = DotDot;
            }
        }
        if(uiFieldIndex == eSTORE_TRANS_TYPE)
        {
            if (strField1.charAt(0) != eTRANTYPE_Pre_Auth)
            {
                strField1 = Empty;
            }
            if (strField2.charAt(0) != eTRANTYPE_Pre_Auth)
            {
                strField2 = Empty;
            }
        }
        if(uiFieldIndex == eSTORE_INVOICE_NUMBER)
        {
            uiInvoiceNum1 = Integer.parseInt(strField1);
            uiInvoiceNum2 = Integer.parseInt(strField2);

            if(uiInvoiceNum1 > uiInvoiceNum2)
            {
                uiReturnValue = 1;
            }
            else if(uiInvoiceNum1 < uiInvoiceNum2)
            {
                uiReturnValue = -1;
            }
            else // if(uiInvoiceNum1 == uiInvoiceNum2)
            {
                uiReturnValue = 0;
            }
        }
        else
        {
            uiReturnValue = strField1.compareTo(strField2);
        }
        return uiReturnValue;
    }

}
